﻿using System;

namespace ComputationalGeometry.Shapes
{
    public static class MathUtility
    {
        /// <summary>
        /// Calculates the distance between two points.
        /// </summary>
        /// <param name="p1">First point.</param>
        /// <param name="p2">Second point.</param>
        /// <returns>The distance between two points.</returns>
        public static double GetDistance(Point2D p1, Point2D p2)
        {
            double xDelta = p1.X - p2.X;
            double yDelta = p1.Y - p2.Y;

            return Math.Sqrt(Math.Pow(xDelta, 2) + Math.Pow(yDelta, 2));
        }

        /// <summary>
        /// Finds the cross product of the 2 vectors created by the 3 vertices.
        /// Vector 1 = v1 -> v2, Vector 2 = v2 -> v3
        /// The vectors make a "right turn" if the sign of the cross product is negative.
        /// The vectors make a "left turn" if the sign of the cross product is positive.
        /// The vectors are colinear (on the same line) if the cross product is zero.
        /// </summary>
        /// <param name="p1">First point.</param>
        /// <param name="p2">Second point.</param>
        /// <param name="p3">Third point.</param>
        /// <returns>Cross product of the two vectors.</returns>
        public static double CrossProduct(Point2D p1, Point2D p2, Point2D p3)
        {
            return (p2.X - p1.X) * (p3.Y - p1.Y) - (p3.X - p1.X) * (p2.Y - p1.Y);
        }

        /// <summary>
        /// Tests if two line segments intersect or not.
        /// The orientation of each line to other line's endpoints is used to determine
        /// the intersection.
        /// </summary>
        /// <param name="line1">Line 1.</param>
        /// <param name="line2">Line 2.</param>
        /// <returns>True if the lines intersect each other.</returns>
        public static bool DoLinesIntersect(Line2D line1, Line2D line2)
        {
            return CrossProduct(line1.InitialPoint, line1.TerminalPoint, line2.InitialPoint) !=
                   CrossProduct(line1.InitialPoint, line1.TerminalPoint, line2.TerminalPoint) ||
                   CrossProduct(line2.InitialPoint, line2.TerminalPoint, line1.InitialPoint) !=
                   CrossProduct(line2.InitialPoint, line2.TerminalPoint, line1.TerminalPoint);
        }

        public static double DistanceFromPointToLine(Point2D point, Line2D line)
        {
            // given a line based on two points, and a point away from the line,
            // find the perpendicular distance from the point to the line.
            // see http://mathworld.wolfram.com/Point-LineDistance2-Dimensional.html
            // for explanation and defination.
            Point2D l1 = line.InitialPoint;
            Point2D l2 = line.TerminalPoint;

            return Math.Abs((l2.X - l1.X)*(l1.Y - point.Y) - (l1.X - point.X)*(l2.Y - l1.Y))/
                    Math.Sqrt(Math.Pow(l2.X - l1.X, 2) + Math.Pow(l2.Y - l1.Y, 2));
        }
    }
}
